#include "expand.h"

Expander::Expander()
{
    mesh = 0;
}

void Expander::setMesh (CMesh *_mesh)
{
    mesh = _mesh;
    myIndex= new Extension::SpatialIndex(mesh);
}

// expand until we have max vertexes
void Expander::max (CVertex *v, int max, vector<CVertex*> *vv)
{
    if (!mesh)
	return;

    vv->clear();
    RingWalker<CMesh> rw = RingWalker<CMesh> (v, mesh);

    do rw.expand (); while (rw.allV.size() < max+1);

    if (rw.allV[0] != v)
        printf ("rw.allV[0] != *v\n");
    vv->reserve ((size_t)max);
    for (int i = 1; i < max+1; i++)
        vv->push_back(rw.allV[i]);

    rw.clear();
}

// expand to the 1-ring
void Expander::ring (CVertex *v, vector<CVertex*> *vv)
{
    if (!mesh)
	return;

    vv->clear();
    RingWalker<CMesh> rw = RingWalker<CMesh> (v, mesh);

    rw.expand ();

    if (rw.allV[0] != v)
        printf ("rw.allV[0] != v\n");
    vv->reserve(rw.allV.size());
    for (int i = 1; i < rw.allV.size(); i++)
        vv->push_back(rw.allV[i]);

    rw.clear();
}

// expand to the k-ring. collect at least min vertexes.
void Expander::kRing (CVertex *v, int k, int min, vector<CVertex*> *vv)
{
    if (!mesh)
	return;

    vv->clear();
    RingWalker<CMesh> rw = RingWalker<CMesh> (v, mesh);

    rw.expand (k);

    if (rw.allV[0] != v)
        printf ("rw.allV[0] != v\n");
    vv->reserve(rw.allV.size());
    for (int i = 1; i < rw.allV.size(); i++)
        vv->push_back(rw.allV[i]);

    rw.clear();

    if (vv->size() < min)
        max (v, min, vv);
}

// expand to a sphere of radius r using breadth. collect at least min vertexes.
void Expander::sphereBreadth (CVertex *v, float r, int min, vector<CVertex*> *vv)
{
    if (!mesh)
	return;

    vv->clear();
    RingWalker<CMesh> rw = RingWalker<CMesh> (v, mesh);

    bool isInside = true;
    while (isInside)
    {
        rw.expand();
        vv->reserve(rw.allV.size());

        vector<CVertex*>::iterator b = rw.lastV.begin();
        vector<CVertex*>::iterator e = rw.lastV.end();
        isInside = false;
        while(b != e)
        {
            if (((*b)->P() - v->P()).Norm() < r)
            {
                vv->push_back(*b);;
                isInside = true;
            }
            ++b;
        }
    }

    rw.clear();

    if (vv->size() < min)
        max (v, min, vv);
}

void Expander::sphereStructure (CVertex *v, float r, vector<CVertex*> *vv)
{
    if (!mesh)
        return;

    vv->clear();

    //SpatialIndex myIndex(mesh);
    
    vector<CVertex> vertices=myIndex->query(*v,r);
    for(vector<CVertex>::iterator it = vertices.begin();it!=vertices.end();it++){
        vv->push_back(&*it);
    }


}

// get all vertexes within a radius r from v.
void Expander::sphereSpace (CVertex *v, float r, vector<CVertex*> *vv)
{
    if (!mesh)
	return;

    vv->clear();

    for(CMesh::VertexIterator vi = mesh->vert.begin(); vi!=mesh->vert.end(); ++vi)
	if (((*vi).P() - v->P()).Norm() < r && &*vi != v)
	    vv->push_back(&*vi);
}
